import torch


# 请查看PyTorchs/7.张量的计算梯度/自动微分模块1.png


# 创建一个需要计算梯度的张量
x = torch.tensor([2.0], requires_grad=True)

# 定义一个简单的函数 y = x^2
y = x ** 2

# 计算 y 相对于 x 的梯度
y.backward()

# 访问 x 的梯度
print(f"x 的梯度: {x.grad}")

# 创建一个需要计算梯度的张量
x = torch.tensor([2.0], requires_grad=True)

# 定义一个简单的函数 y = x^2
y = x ** 2

# 计算 y 相对于 x 的梯度
y.backward()

# 访问 x 的梯度
print(f"x 的梯度: {x.grad}")

# todo 关于上方的代码可以看 backward代码解释.png




def test01():
    # todo 代码详细解释请看PyTorchs/7.张量的计算梯度/自动微分详细解释2.png
    # 1. 当X为标量时梯度的计算
    x = torch.tensor(5)
    # 目标值
    y= torch.tensor(0)
    # 设置要更新的权重和偏置的初始值
    w = torch.tensor(1, requires_grad=True, dtype=torch.float32)
    b = torch.tensor(1, requires_grad=True, dtype=torch.float32)
    # 设置网络的输出值
    z = x * w + b # 矩阵乘法
    # 设置损失函数，并进行损失的计算
    loss = torch.nn.MSELoss()
    loss = loss(z, y)
    # 自动微分， 计算损失函数关于w和b的梯度
    loss.backward()
    # 打印梯度
    # 打印w，b变量的梯度
    # backward()函数计算的梯度值会存储在张量的grad属性中
    print('W的梯度',w.grad)
    print('b的梯度',b.grad)


def test02():
    # 输入张量2*5
    x = torch.ones(2,5)
    # 目标值是2*3
    y = torch.zeros(2,3)
    # 设置要更新的权重和偏置的初始值
    w = torch.randn(5,3, requires_grad=True)
    b = torch.randn(3, requires_grad=True)
    # 设置网络的输出值
    z = torch.matmul(x,w)+b # 矩阵乘法
    # 设置损失函数，并进行损失的计算
    loss = torch.nn.MSELoss()
    loss = loss(z, y)
    # 自动微分， 计算损失函数关于w和b的梯度
    loss.backward()
    # 打印梯度
    # 打印w，b变量的梯度
    # backward()函数计算的梯度值会存储在张量的grad属性中
    print('W的梯度',w.grad)
    print('b的梯度',b.grad)


# todo 总结：自动微分模块计算梯度，需要满足两个条件
#  1. 需要计算梯度的张量需要设置requires_grad=True
#  2. 需要计算梯度的张量需要参与运算，即需要计算梯度
#  3. 需要计算梯度的张量需要设置初始值
